AWS CloudFormation ネストされたスタックの変更セットの実行方法
はじめに
こんにちは、あるいはこんばんは なかはらです。
CloudFormation使ってますか?AWSリソースをコード化し、便利にAWS環境を構築できるのでよく利用しています。設定変更や管理のしやすさを考えてテンプレートをサービスや機能単位で分割し、ネストさせていますが、設定変更する前の変更セットを使ったチェックを実行するとネストされたスタックの変更対象が表示されません。
今回は、ネストされたスタックの変更セットで変更対象が確認できる方法を書き留めておきます。
ルートスタックの変更セットの場合
まずはルートスタックから変更セットを実行するとどうなるのか、確認していきます。VPC、セキュリティグループ(SG)に分割したテンプレートを用意し、ネストされたスタックを作成しました。
test-stack.yml
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
SystemName:
Type: String
MinLength: 1
MaxLength: 10
Default: test
EnvironmentName:
Description: environment name
Type: String
AllowedValues:
- dev
- stg
- prd
Default: dev
Resources:
VPC:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: "https://S3バケットFQDN/dev/vpc.yml"
Parameters:
SystemName: !Sub ${SystemName}
EnvironmentName: !Sub ${EnvironmentName}
SG:
Type: AWS::CloudFormation::Stack
DependsOn: VPC
Properties:
TemplateURL: "https://S3バケットFQDN/dev/sg.yml"
Parameters:
SystemName: !Sub ${SystemName}
EnvironmentName: !Sub ${EnvironmentName}
vpc.yml
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
SystemName:
Type: String
MinLength: 1
MaxLength: 10
Default: test
EnvironmentName:
Description: environment name
Type: String
AllowedValues:
- dev
- stg
- prd
Default: dev
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.250.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-vpc
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-igw
DHCPOptions:
Type: AWS::EC2::DHCPOptions
Properties:
DomainName: ap-northeast-1.compute.internal
DomainNameServers:
- AmazonProvidedDNS
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-dopt
DHCPOptionsAssociation:
Type: AWS::EC2::VPCDHCPOptionsAssociation
Properties:
VpcId: !Ref VPC
DhcpOptionsId: !Ref DHCPOptions
RouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-front-rtb
Route:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTable1
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
AttachInternetGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
NetworkAcl1:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VPC
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-nacl
NetworkAclEntry1:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAcl1
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: true
CidrBlock: 0.0.0.0/0
Icmp:
Code: -1
Type: -1
PortRange:
From: -1
To: -1
NetworkAclEntry2:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAcl1
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: false
CidrBlock: 0.0.0.0/0
Icmp:
Code: -1
Type: -1
PortRange:
From: -1
To: -1
NetworkAclAssociation1:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref Subnet1
NetworkAclId: !Ref NetworkAcl1
Subnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: 10.11.0.0/24
VpcId: !Ref VPC
MapPublicIpOnLaunch: false
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-front-a-subnet
Subnet1RouteTableAssciation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref Subnet1
RouteTableId: !Ref RouteTable1
Outputs:
VPC:
Value: !Ref VPC
Export:
Name: !Sub ${SystemName}-${EnvironmentName}-vpc
Subnet1:
Value: !Ref Subnet1
Export:
Name: !Sub ${SystemName}-${EnvironmentName}-subnet1
sg.yml
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
SystemName:
Type: String
MinLength: 1
MaxLength: 10
Default: test
EnvironmentName:
Description: environment name
Type: String
AllowedValues:
- dev
- stg
- prd
Default: dev
Resources:
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: {"Fn::ImportValue": !Sub "${SystemName}-${EnvironmentName}-vpc"}
GroupDescription: EC2SG
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-ec2-sg
EC2SGIngress1:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref EC2SG
IpProtocol: tcp
FromPort: 22
ToPort: 22
SourceSecurityGroupId: !Ref EC2SG
Outputs:
EC2SG:
Value: !Ref EC2SG
Export:
Name: !Sub ${SystemName}-${EnvironmentName}-ec2-sg
S3バケットにVPC、SGのテンプレートを格納し、CloudFormationでルートスタックを実行するとNested Stackの完成です。
ここからセキュリティグループのインバウンドルールを追加(EC2SGIngress2を追加)しました。
sg.yml
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
SystemName:
Type: String
MinLength: 1
MaxLength: 10
Default: test
EnvironmentName:
Description: environment name
Type: String
AllowedValues:
- dev
- stg
- prd
Default: dev
Resources:
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: {"Fn::ImportValue": !Sub "${SystemName}-${EnvironmentName}-vpc"}
GroupDescription: EC2SG
Tags:
-
Key: Name
Value: !Sub ${SystemName}-${EnvironmentName}-ec2-sg
EC2SGIngress1:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref EC2SG
IpProtocol: tcp
FromPort: 22
ToPort: 22
SourceSecurityGroupId: !Ref EC2SG
EC2SGIngress2:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref EC2SG
IpProtocol: tcp
FromPort: 1024
ToPort: 65525
SourceSecurityGroupId: !Ref EC2SG
Outputs:
EC2SG:
Value: !Ref EC2SG
Export:
Name: !Sub ${SystemName}-${EnvironmentName}-ec2-sg
S3バケットに格納してルートスタックから変更セットを実施してみます。
VPC、SGどちらのスタックもModifyとなってしまいました。ルートスタックからだとネストされたスタックのどのリソースが変更されたか確認することができません。また、ルートスタックのテンプレートを変更していないのにModifyになってしまう為、VPCスタックもなにか更新されてしまうのか?と勘違いしてしまいます。ネストされたスタック管理の悩ましいところです。
ネストされたスタックの変更セット
ルートスタックではなく、ネストされたスタックに対して変更セットを実施すればいいんじゃないかと考えてやってみました。
ネストされたSGスタックから「既存スタックの変更セットの作成」をクリックします。
ネストされたスタックから操作すると以下のポップアップが必ず表示されます。ルートスタックから更新されないと正しく更新できなくなる可能性があります。例えばルートスタックから渡されたパラメータを使ったResourcesがネストされたスタックにある場合、エラーとなってしまいます。今回は、ネストされたスタックのテンプレートにも同じParametersを用意している且つ、変更セットで変更対象を確認する操作なので既存のスタックに影響はない(はず)です。
「ネストされたスタックの変更セットを作成する」をチェックし、「変更セットの作成」をクリックします。
更新したテンプレートの変更を確認したいので、「既存テンプレートを置き換える」をチェックしてください。Amazon S3 URLまたはテンプレートファイルのアップロードを選択し、テンプレートを指定してください。
操作を進めて変更セットを作成すると変更対象を確認することができます。
注意事項としては、この画面では「実行」せず、変更セットを「削除」してください。さきほどのポップアップでも記載されている通り、更新はルートスタックから実行するのが推奨です。
終わりに
ルートスタックから確認できるのが望ましいのですが、現時点では確認することができません。ネストされたスタックだけで変更セットが実行できるようにParametersやOutputsなどを活用し、ネストされたスタックだけで実行できるようにテンプレートを作成すれば変更対象を確認することができます。